在現代軟體開發中,安全地管理憑證是一個關鍵挑戰。本文將介紹如何使用 HashiCorp Vault 來管理 Golang 應用程序和 GitLab CI/CD 流程中的敏感信息。我們將基於之前的 Golang Web 應用和 GitLab CI 配置,展示如何整合 Vault 以提高安全性。
首先,我們需要在 Vault 中設置適當的密鑰和策略。
# 為 Golang 應用創建密鑰
vault kv put secret/myapp/config DB_PASSWORD=mypassword API_KEY=myapikey
# 為 GitLab CI 創建密鑰
vault kv put secret/myapp/ci KUBE_CONFIG=<base64_encoded_kubeconfig>
vault kv put secret/myapp/docker DOCKER_PASSWORD=mydockerhubpassword
# myapp-policy.hcl
path "secret/data/myapp/config" {
capabilities = ["read"]
}
path "secret/data/myapp/ci" {
capabilities = ["read"]
}
path "secret/data/myapp/docker" {
capabilities = ["read"]
}
應用策略:
vault policy write myapp-policy myapp-policy.hcl
對於 Kubernetes 環境:
vault write auth/kubernetes/role/myapp \
bound_service_account_names=myapp-sa \
bound_service_account_namespaces=default \
policies=myapp-policy \
ttl=1h
我們需要修改 Golang 應用以使用 Vault 客戶端庫。
go get github.com/hashicorp/vault/api
package main
import (
"fmt"
"net/http"
"os"
"github.com/hashicorp/vault/api"
)
func getSecret(key string) (string, error) {
config := &api.Config{
Address: os.Getenv("VAULT_ADDR"),
}
client, err := api.NewClient(config)
if err != nil {
return "", err
}
token := os.Getenv("VAULT_TOKEN")
client.SetToken(token)
secret, err := client.Logical().Read("secret/data/myapp/config")
if err != nil {
return "", err
}
data, ok := secret.Data["data"].(map[string]interface{})
if !ok {
return "", fmt.Errorf("Data not found")
}
value, ok := data[key].(string)
if !ok {
return "", fmt.Errorf("Key not found")
}
return value, nil
}
func handler(w http.ResponseWriter, r *http.Request) {
apiKey, err := getSecret("API_KEY")
if err != nil {
http.Error(w, "Error retrieving secret", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "Hello, World from Golang! API Key: %s", apiKey)
}
func main() {
http.HandleFunc("/", handler)
fmt.Println("Server starting on port 8080...")
http.ListenAndServe(":8080", nil)
}
我們需要確保 Vault 客戶端在容器中可用:
FROM golang:1.16-alpine AS builder
WORKDIR /app
COPY . .
RUN apk add --no-cache git && \
go get github.com/hashicorp/vault/api && \
go build -o main .
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
修改 deployment.yaml 以包含 Vault 代理注入:
apiVersion: apps/v1
kind: Deployment
metadata:
name: golang-web-app
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config"
vault.hashicorp.com/role: "myapp"
spec:
replicas: 1
selector:
matchLabels:
app: golang-web-app
template:
metadata:
labels:
app: golang-web-app
spec:
serviceAccountName: myapp-sa
containers:
- name: golang-web-app
image: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}
ports:
- containerPort: 8080
env:
- name: VAULT_ADDR
value: "http://vault:8200"
修改 .gitlab-ci.yml 以使用 Vault:
stages:
- build
- deploy
variables:
VAULT_ADDR: "http://vault:8200"
build:
stage: build
image: docker:20.10.16
services:
- docker:20.10.16-dind
script:
- apk add --no-cache curl jq
- |
VAULT_TOKEN=$(curl -s -X POST ${VAULT_ADDR}/v1/auth/jwt/login -d "{\"role\":\"myapp\",\"jwt\":\"$CI_JOB_JWT\"}" | jq -r '.auth.client_token')
- |
DOCKER_PASSWORD=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" ${VAULT_ADDR}/v1/secret/data/myapp/docker | jq -r '.data.data.DOCKER_PASSWORD')
- echo $DOCKER_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
deploy:
stage: deploy
image:
name: bitnami/kubectl:latest
entrypoint: ['']
script:
- apk add --no-cache curl jq
- |
VAULT_TOKEN=$(curl -s -X POST ${VAULT_ADDR}/v1/auth/jwt/login -d "{\"role\":\"myapp\",\"jwt\":\"$CI_JOB_JWT\"}" | jq -r '.auth.client_token')
- |
KUBE_CONFIG=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" ${VAULT_ADDR}/v1/secret/data/myapp/ci | jq -r '.data.data.KUBE_CONFIG')
- echo $KUBE_CONFIG | base64 -d > kubeconfig
- export KUBECONFIG=kubeconfig
- sed -i "s|${CI_REGISTRY_IMAGE}|${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA}|g" deployment.yaml
- kubectl apply -f deployment.yaml
通過將 Vault 整合到 Golang 應用和 GitLab CI/CD 流程中,我們大大提高了憑證管理的安全性和靈活性。這種方法允許集中管理敏感信息,減少了憑證洩露的風險,並簡化了密鑰輪換過程。
然而,正確實施這種集成需要仔細的規劃和持續的維護。確保定期審查和更新您的 Vault 策略和實踐,以應對不斷變化的安全威脅。
通過採用這些最佳實踐,您可以創建一個更安全、更可管理的基礎設施,為您的應用程序和部署流程提供強大的保護。